//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<editor.cpp>
///	@path	~/src/editor/
///	@date	2008/05/16
///	@desc	.

// Override config.h as we had already included it in editor.h
#include "editor/editor.h"

#include "lib/utilities/observer.h"

#include "editor/editor_engine.h"

#if ( WINVER >= 0x0600 )
#	pragma message("Build with Windows SDK 0x0600")
#elif ( WINVER >= 0x0500 )
#	pragma message("Build with Windows SDK 0x0500")
#endif

#include "wm/MainFrm.h"

#define ISOLATION_AWARE_ENABLED 1
#include <commctrl.h> // for InitCommonControls() 
#include <shellapi.h> // for ExtractIcon()

using namespace xeres;
using namespace Gdiplus;

#pragma comment( lib , "gdiPlus.lib" )

// Message loop that ticks engine.
class XMessageLoop : public CMessageLoop
{
public:

	// override message loop's run
	int Run( HWND hWnd )
	{
		BOOL bDoIdle = TRUE , bRet = FALSE;
		int nIdleCount = 0;
		bool bGotMsg;

		Counter last = Counter::Now();
		const int gap = static_cast<int>( 1000.f / 30.f );
		::SetTimer( hWnd , TIMER_TICK , gap , NULL );

		m_msg.message = WM_NULL;
		// message loop
		{
			while( WM_QUIT != m_msg.message )
			{
				bool run = false;
				// Use PeekMessage() so we can use idle time to render the scene. 
				bGotMsg = ( ::PeekMessage( &m_msg, NULL, 0U, 0U, PM_NOREMOVE ) != FALSE );
				if( bDoIdle && !bGotMsg )
				{
					if( !OnIdle(nIdleCount++) )
						bDoIdle = FALSE;
				}
				
				bRet = ::GetMessage( &m_msg, NULL, 0, 0 );
				if(bRet == -1)
				{
					ATLTRACE2(atlTraceUI, 0, _T("::GetMessage returned -1 (error)\n"));
					continue;   // error, don't process
				}
				else if(!bRet)
				{
					ATLTRACE2(atlTraceUI, 0, _T("XMessageLoop::Run - exiting\n"));
					break;   // WM_QUIT, exit message loop
				}

				run = ( m_msg.hwnd == hWnd && m_msg.message == WM_TIMER && m_msg.wParam == TIMER_TICK );

				// Translate and dispatch the message
				if( !PreTranslateMessage(&m_msg) )
				{
					::TranslateMessage(&m_msg);
					::DispatchMessage(&m_msg);
				}
				
				Counter current = Counter::Now();
				if( run && ( ( current - last ).ToMilliSecond() > gap ) && ::IsWindow( hWnd ) )
				{ // game loop
					COUNTER_SCOPE( _S("*counter/app") );
					{
						// update frame
						XEditor::instance().engine().UpdateFrame();
					}
					COUNTER_END();
					// clear states
					CounterObserver::NextFrame();
					last = current;
				}

				if( IsIdleMessage(&m_msg) )
				{
					bDoIdle = TRUE;
					nIdleCount = 0;
				}
			}
		}
		return (int)m_msg.wParam;
	}
};

int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)
{
	XMessageLoop theLoop;
	__AppModule.AddMessageLoop(&theLoop);

	XMainFrame wndMain;

	if(wndMain.CreateEx() == NULL)
	{
		ATLTRACE(_T("Main window creation failed!\n"));
		return 0;
	}

	// Initialize engine.
	xeres::editor::wm().AttachMainView( wndMain.m_hWnd , &wndMain.GetMain() );
	xeres::XEditor::instance().Initialize( &wndMain.GetMain().GetWorkspace().GetEngineView() );

	wndMain.ShowWindow(nCmdShow);

	int nRet = theLoop.Run( wndMain.m_hWnd );

	__AppModule.RemoveMessageLoop();

	// Finalize engine.
	xeres::XEditor::instance().Finalize();

	return nRet;
}

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
{
	// Initialize GDI+.
	GdiplusStartupInput gdiplusStartupInput;
	memset( &gdiplusStartupInput , 0 , sizeof(GdiplusStartupInput) );

	gdiplusStartupInput.GdiplusVersion = 1;
	gdiplusStartupInput.DebugEventCallback = NULL;
	gdiplusStartupInput.SuppressBackgroundThread = FALSE;
	gdiplusStartupInput.SuppressExternalCodecs = FALSE;

	ULONG_PTR gdiplusToken;
	GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

	HRESULT hRes = ::CoInitialize(NULL);
	XS_ASSERT(SUCCEEDED(hRes));

	::AtlInitCommonControls(ICC_BAR_CLASSES);	// add flags to support other controls

	hRes = __AppModule.Init(NULL, hInstance);
	ATLASSERT(SUCCEEDED(hRes));

	int nRet = Run(lpstrCmdLine, nCmdShow);

	__AppModule.Term();
	::CoUninitialize();

	// shut down GDI+
	GdiplusShutdown(gdiplusToken);

	// wait for all resource released
	::Sleep( 0 );

	return nRet;
}
